/*
 * Copyright (c) 2020-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"
#include "hi_io.h"
#include "iot_errno.h"
#include "hi_adc.h"

float particleLevel, sensorVoltage;
int rawADCValue;
#define CONVERSION_FACTOR 0.03 
#define CLEAN_AIR_VOLTAGE 230 
#define REFERENCE_VOLTAGE 7200 

//滑动窗口滤波算法
double SmoothData(int newSample)
{
    static int isInitialized = 0, sampleBuffer[10], bufferSum;
    const int WINDOW_SIZE = 10;
    int i;
  
    if (!isInitialized)
    {
        isInitialized = 1;
        for (i = 0, bufferSum = 0; i < WINDOW_SIZE; i++)
        {
            sampleBuffer[i] = newSample;
            bufferSum += sampleBuffer[i];
        }
    }
    else
    {
        bufferSum -= sampleBuffer[0];
        for (i = 0; i < (WINDOW_SIZE - 1); i++)
        {
            sampleBuffer[i] = sampleBuffer[i + 1];
        }
        sampleBuffer[9] = newSample;
        bufferSum += sampleBuffer[9];
    }
    return bufferSum / 10.0;
}

/***** 传感器电压读取函数 *****/
unsigned int ReadSensorVoltage(void)
{
    unsigned int status;
    unsigned short adcData;
    status = hi_adc_read(HI_ADC_CHANNEL_2, &adcData, HI_ADC_EQU_MODEL_8, HI_ADC_CUR_BAIS_DEFAULT, 0xff);
    if (status != IOT_SUCCESS)
        printf("Sensor Voltage Read Error\n");
    return adcData;
}

double CalculateParticleDensity(void)
{
    IoTGpioSetOutputVal(HI_IO_NAME_GPIO_7, 1); // 激活传感器
    usleep(280);
    rawADCValue = ReadSensorVoltage();
    IoTGpioSetOutputVal(HI_IO_NAME_GPIO_7, 0); // 关闭传感器
  
    rawADCValue = SmoothData(rawADCValue);
    sensorVoltage = (REFERENCE_VOLTAGE / 4096.0) * rawADCValue * 11;
  
    if(sensorVoltage >= CLEAN_AIR_VOLTAGE)
    {
        sensorVoltage -= CLEAN_AIR_VOLTAGE;
        particleLevel = sensorVoltage * CONVERSION_FACTOR;
    }
    else
        particleLevel = 0;
    return particleLevel;
}

static void ParticleMonitorTask(void)
{
    //初始化传感器控制引脚
    IoTGpioInit(HI_IO_NAME_GPIO_0);
    hi_io_set_func(HI_IO_NAME_GPIO_7, HI_IO_FUNC_GPIO_7_GPIO);
    IoTGpioSetDir(HI_IO_NAME_GPIO_7, IOT_GPIO_DIR_OUT);
    IoTGpioSetOutputVal(HI_IO_NAME_GPIO_7, 0);
  
    while(1)
    {  
        printf("Current PM2.5 Level: %4.2f ug/m3\n", CalculateParticleDensity());
        sleep(1);
    }
}

static void InitParticleMonitor(void)
{
    osThreadAttr_t taskConfig;
    taskConfig.attr_bits = 0U;
    taskConfig.cb_mem = NULL;
    taskConfig.cb_size = 0U;
    taskConfig.stack_mem = NULL;
    taskConfig.stack_size = 1024 * 4;

    taskConfig.name = "ParticleMonitor";
    taskConfig.priority = 25;
    if(osThreadNew((osThreadFunc_t)ParticleMonitorTask, NULL, &taskConfig) == NULL)
    {
        printf("Failed to initialize particle monitor!\n");
    }
}
APP_FEATURE_INIT(InitParticleMonitor);
